﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;

using ActiproContrib.Windows;

using ActiproSoftware.Windows.Controls;
using ActiproSoftware.Windows.Media;
using ActiproSoftware.Windows.Controls.Ribbon.UI;

namespace SupremacyEditor
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App
    {
        static App()
        {
            /*
             * Register an event handler for the ContextMenu.Opened event.  This handler will
             * ensure that the ContextMenu style for the current theme is applied to every
             * ContextMenu using the default style.  We do this because some controls, like
             * the TextBox, provide a default ContextMenu of a derived type.  Implicit styles
             * are not applied to these menus, so we must apply the desired styles manually.
             */
            EventManager.RegisterClassHandler(
                typeof(ContextMenu),
                ContextMenu.OpenedEvent,
                (RoutedEventHandler)OnContextMenuOpened,
                true);

            /*
             * Register an event handler for the Thumb.DragDeltaEvent event.  This handler
             * listens for drag events from resize grips used within Popups (such as those
             * used by the ComboBox control) and resize the ancestor Popup accordingly.
             */
            EventManager.RegisterClassHandler(
                typeof(Thumb),
                Thumb.DragDeltaEvent,
                (DragDeltaEventHandler)OnPopupResizeGripDragDelta,
                true);

            /*
             * Register an event handler for the MouseDoubleClickEvent event for the Thumb
             * control.  This handler resets a PopUp to its default size when the user
             * double-clicks the resize grip.
             */
            EventManager.RegisterClassHandler(
                typeof(Thumb),
                Control.MouseDoubleClickEvent,
                (MouseButtonEventHandler)OnPopupResizeGripMouseDoubleClick,
                true);
        }
        public App()
        {
            var bootStrapper = new Bootstrapper();
            bootStrapper.Run();
        }

        #region IsPopupWidthOverridden Property
        private static readonly DependencyPropertyKey IsPopupWidthOverriddenPropertyKey = DependencyProperty.
            RegisterAttachedReadOnly(
            "IsPopupWidthOverridden",
            typeof(bool),
            typeof(App),
            new FrameworkPropertyMetadata(
                false,
                FrameworkPropertyMetadataOptions.None));

        private static readonly DependencyProperty IsPopupWidthOverriddenProperty =
            IsPopupWidthOverriddenPropertyKey.DependencyProperty;

        // ReSharper disable SuggestBaseTypeForParameter
        private static bool GetIsPopupWidthOverridden(Popup source)
        {
            if (source == null)
                throw new ArgumentNullException("source");
            return (bool)source.GetValue(IsPopupWidthOverriddenProperty);
        }

        private static void SetIsPopupWidthOverridden(Popup source, bool value)
        {
            if (source == null)
                throw new ArgumentNullException("source");
            source.SetValue(IsPopupWidthOverriddenPropertyKey, value);
        }

        // ReSharper restore SuggestBaseTypeForParameter
        #endregion

        #region IsPopupHeightOverridden Property
        private static readonly DependencyPropertyKey IsPopupHeightOverriddenPropertyKey = DependencyProperty.
            RegisterAttachedReadOnly(
            "IsPopupHeightOverridden",
            typeof(bool),
            typeof(App),
            new FrameworkPropertyMetadata(
                false,
                FrameworkPropertyMetadataOptions.None));

        private static readonly DependencyProperty IsPopupHeightOverriddenProperty =
            IsPopupHeightOverriddenPropertyKey.DependencyProperty;

        // ReSharper disable SuggestBaseTypeForParameter
        private static bool GetIsPopupHeightOverridden(Popup source)
        {
            if (source == null)
                throw new ArgumentNullException("source");
            return (bool)source.GetValue(IsPopupHeightOverriddenProperty);
        }

        private static void SetIsPopupHeightOverridden(Popup source, bool value)
        {
            if (source == null)
                throw new ArgumentNullException("source");
            source.SetValue(IsPopupHeightOverriddenPropertyKey, value);
        }

        // ReSharper restore SuggestBaseTypeForParameter
        #endregion

        #region Event Handlers
        private static void OnContextMenuOpened(object sender, RoutedEventArgs e)
        {
            var contextMenu = sender as ContextMenu;
            if (contextMenu == null)
                return;

            var contextMenuType = contextMenu.GetType();

            if ((contextMenuType == typeof(ContextMenu)) ||
                (contextMenuType == typeof(ActiproSoftware.Windows.Controls.Ribbon.Controls.ContextMenu)))
            {
                return;
            }

            var styleValueSource = DependencyPropertyHelper.GetValueSource(contextMenu, FrameworkElement.StyleProperty);
            if (styleValueSource.BaseValueSource == BaseValueSource.Default)
                contextMenu.SetResourceReference(FrameworkElement.StyleProperty, typeof(ContextMenu));
        }

        private static void OnPopupResizeGripMouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            var resizeGrip = sender as Thumb;
            if ((resizeGrip == null) || !ComboBoxExtensions.GetIsPopupResizeGrip(resizeGrip))
                return;

            var popup = VisualTreeHelperExtended.GetAncestorPopup(resizeGrip);
            if (popup == null)
                return;

            var isWidthOverridden = GetIsPopupWidthOverridden(popup);
            var isHeightOverridden = GetIsPopupHeightOverridden(popup);

            if (!isWidthOverridden && !isHeightOverridden)
                return;

            var scrollViewer = popup.FindVisualDescendantByType<ScrollViewer>();
            if (scrollViewer == null)
                return;

            if (isWidthOverridden)
            {
                scrollViewer.ClearValue(FrameworkElement.WidthProperty);
                scrollViewer.ClearValue(IsPopupWidthOverriddenPropertyKey);
            }

            if (isHeightOverridden)
            {
                scrollViewer.ClearValue(FrameworkElement.HeightProperty);
                scrollViewer.ClearValue(IsPopupHeightOverriddenPropertyKey);
            }
        }

        private static void OnPopupResizeGripDragDelta(object sender, DragDeltaEventArgs e)
        {
            var resizeGrip = sender as Thumb;
            if ((resizeGrip == null) || !ComboBoxExtensions.GetIsPopupResizeGrip(resizeGrip))
                return;

            var popup = VisualTreeHelperExtended.GetAncestorPopup(resizeGrip);
            if (popup == null)
                return;

            var popupAnchor = resizeGrip.TemplatedParent;
            if (popupAnchor == null)
                return;

            var scrollViewer = popup.FindVisualDescendantByType<ScrollViewer>();
            if (scrollViewer == null)
                return;

            var resizeMode = PopupControlService.GetPopupResizeMode(popupAnchor);

            var allowVerticalResize = (resizeMode == ControlResizeMode.Vertical) ||
                                      (resizeMode == ControlResizeMode.Both);
            var allowHorizontalResize = (resizeMode == ControlResizeMode.Horizontal) ||
                                        (resizeMode == ControlResizeMode.Both);

            if (!allowHorizontalResize && !allowVerticalResize)
                return;

            var maximumWidth = double.PositiveInfinity;
            var maximumHeight = double.PositiveInfinity;

            var childElement = popup.Child;
            if (childElement != null)
            {
                var tempWidth = scrollViewer.ReadLocalValue(FrameworkElement.WidthProperty);
                var tempHeight = scrollViewer.ReadLocalValue(FrameworkElement.HeightProperty);

                scrollViewer.ClearValue(FrameworkElement.WidthProperty);
                scrollViewer.ClearValue(FrameworkElement.HeightProperty);

                childElement.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));

                maximumWidth = childElement.DesiredSize.Width;
                maximumHeight = childElement.DesiredSize.Height;

                scrollViewer.SetValue(FrameworkElement.WidthProperty, tempWidth);
                scrollViewer.SetValue(FrameworkElement.HeightProperty, tempHeight);
            }

            if (allowHorizontalResize)
            {
                var minimumWidth = SystemParameters.HorizontalScrollBarButtonWidth * 2;
                if (!double.IsNaN(popup.MaxWidth))
                {
                    maximumWidth = double.IsInfinity(maximumWidth)
                                       ? popup.MaxWidth
                                       : Math.Min(popup.MaxWidth, maximumWidth);
                }
                scrollViewer.Width = Math.Min(
                    Math.Max(
                        scrollViewer.ActualWidth + e.HorizontalChange,
                        minimumWidth),
                    maximumWidth);
                SetIsPopupWidthOverridden(popup, true);
            }

            if (allowVerticalResize)
            {
                var minimumHeight = SystemParameters.VerticalScrollBarButtonHeight * 2;
                if (!double.IsNaN(popup.MaxHeight))
                {
                    maximumHeight = double.IsInfinity(maximumHeight)
                                        ? popup.MaxHeight
                                        : Math.Min(popup.MaxHeight, maximumHeight);
                }
                scrollViewer.Height = Math.Min(
                    Math.Max(
                        scrollViewer.ActualHeight + e.VerticalChange,
                        minimumHeight),
                    maximumHeight);
                SetIsPopupHeightOverridden(popup, true);
            }
        }
        #endregion
    }
}
